package com.sunriz.refreshhcdata.server.Impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sunriz.refreshhcdata.POJO.DataCompareDO;
import com.sunriz.refreshhcdata.POJO.DispatchLog;
import com.sunriz.refreshhcdata.POJO.InfoStorageDO;
import com.sunriz.refreshhcdata.POJO.McHcRelationshipDO;
import com.sunriz.refreshhcdata.mapper.DataCompareMapper;
import com.sunriz.refreshhcdata.mapper.DispatchLogMapper;
import com.sunriz.refreshhcdata.mapper.InfoStorageMapper;
import com.sunriz.refreshhcdata.mapper.McHcRelationshipMapper;
import com.sunriz.refreshhcdata.server.CompareServer;
import com.sunriz.refreshhcdata.utils.ExcelAppender;
import com.sunriz.refreshhcdata.utils.NumericalConversion;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ClassName: CompareServerImpl
 * Package: com.sunriz.refreshhcdata.server.Impl
 * Description:
 *
 * @Author BuTang
 * @Create 2024/10/16 14:30
 * @Version 1.0
 */
@Service
@Slf4j
public class CompareServerImpl implements CompareServer {
    @Autowired
    McHcRelationshipMapper mcHcRelationshipMapper;

    final InfoStorageMapper infoStorageMapper;
    final DataCompareMapper dataCompareMapper;
    final DispatchLogMapper dispatchLogMapper;
    private Map<String, McHcRelationshipDO> relationMap;
    private static Map<String,Integer> ERROR_MAP;

    // 输出到excel
    private ExcelAppender excelAppender;

    public CompareServerImpl(DispatchLogMapper dispatchLogMapper, DataCompareMapper dataCompareMapper, InfoStorageMapper infoStorageMapper) {
        this.dispatchLogMapper = dispatchLogMapper;
        this.dataCompareMapper = dataCompareMapper;
        this.infoStorageMapper = infoStorageMapper;
        excelAppender = new ExcelAppender();
        excelAppender.appendRow(new String[]{"数据项","下发值","上报值","结果（通过/失败）"});
        ERROR_MAP = new HashMap();
    }


    // 使用 @PostConstruct 确保所有依赖项注入完成后再执行初始化
    @PostConstruct
    public void init() {
        List<McHcRelationshipDO> allInfo = mcHcRelationshipMapper.getAllInfo();

        // 将关系表转换为key-value的形式
        relationMap = new HashMap<>();
        allInfo.forEach(mcHcRelationshipDO -> {
            String hcPropertyKey = mcHcRelationshipDO.getHcPropertyKey();
            relationMap.put(hcPropertyKey, mcHcRelationshipDO);
        });

        log.info("Relation map initialized with {} entries.", relationMap.size());
    }


    @Override
    public void startCompare(String deviceCode) {

        //1.  判断存储的数据库`info_storage`数据库是否存在该数据，存在泽继续
        List<String> dataCompareDeviceCodeList = dataCompareMapper.getDeviceCodeList();
        if (!dataCompareDeviceCodeList.contains(deviceCode)) {
            // 不存在该数据，新增该数据，上报数量+1
            dataCompareMapper.insertInfo(new DataCompareDO(deviceCode, LocalDateTime.now(), 0, 0, 0, 0, 1));
            log.info("`info_storage`数据库不存在device_code为{}数据，新增该数据，上报数量+1", deviceCode);
        }

        //2.  获取上报后存储的deviceCode的数据
        InfoStorageDO infoStorage = infoStorageMapper.getByDeviceCode(deviceCode);

        //3.  获取下发时存储的deviceCode的数据
        List<String> deviceCodeList = dispatchLogMapper.getDeviceCodeList();
        boolean contains = deviceCodeList.contains(deviceCode);

        // 判断`dispatch_log`表内是否有对应的数据，若不存在则新增数据
        if (!contains) {
            log.info("下发数据不存在，不记录该次上报数据");
            return;
        }
        int sameCount = 0;
        int diffCount = 0;
        int totalCount = 0;

        // 开始比较，上报表
        String storageJson = infoStorage.getDeviceJson();

        DispatchLog dispatchLog = dispatchLogMapper.getByDeviceCode(deviceCode);
        String dispatchJson = dispatchLog.getDeviceJson();
        if (dispatchJson == null) {
            log.info("下发数据不存在，不记录该次上报数据");
            return;
        }


        // 使用 Jackson 的 ObjectMapper 将 JSON 字符串转换为 Map
        ObjectMapper objectMapper = new ObjectMapper();

        Map<String, Object> storageMap = null;
        Map<String, Object> dispatchMap = null;

        try {
            storageMap = objectMapper.readValue(storageJson, Map.class);
            dispatchMap = objectMapper.readValue(dispatchJson, Map.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


        // 比较两个 Map 中相同的键的值
        for (String key : dispatchMap.keySet()) {
            Object writeValue = dispatchMap.get(key);
            // 上报的数据中，有包含下发的数据
            if (storageMap.containsKey(key)) {
                Object storageValue = storageMap.get(key);
                try {
                    if (Double.valueOf(storageValue.toString()).equals(Double.valueOf((String) writeValue))) {
                        sameCount++;
                        totalCount++;

                        log.info("key：{}, 下发的值为：{}, 上报的值为：{} ",key,writeValue.toString(),storageValue.toString());



                        excelAppender.appendRow(new String[]{key,writeValue.toString(),storageValue.toString(),"通过"});

                    } else {
                        diffCount++;
                        totalCount++;

                        log.error("key：{}, 下发的值为：{}, 上报的值为：{} ",key,writeValue.toString(),storageValue.toString());
                        excelAppender.appendRow(new String[]{key,writeValue.toString(),storageValue.toString(),"未通过"});

                        // 错误计数
                        if (ERROR_MAP.containsKey(key)) {
                            Integer integer = ERROR_MAP.get(key);
                            ERROR_MAP.put(key,integer+=1);
                        }else {
                            ERROR_MAP.put(key,1);
                        }
                    }
                } catch (NullPointerException e) {
                    log.error("下发的数据中中不包含为：{} 的key", key);
                }
            }else{
                excelAppender.appendRow(new String[]{key,writeValue.toString(),"","未通过"});
            }
        }

        String[] keyValueArray = ERROR_MAP.entrySet()
                .stream()
                .map(entry -> entry.getKey() + "=" + entry.getValue())
                .toArray(String[]::new);

        excelAppender.appendRow(keyValueArray);
        excelAppender.save();


        log.info("==============================================================================================================================================================================");


        DataCompareDO dataCompareDO = new DataCompareDO(deviceCode, LocalDateTime.now(), sameCount, diffCount, totalCount, 0, 1);
        dataCompareMapper.updateInfo(dataCompareDO);
    }


    @Override
    public void dispatchLog(DispatchLog dispatchLog) {

        String deviceJson = dispatchLog.getDeviceJson();

        // 判断下发的数据格式是否是Map
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            JsonNode jsonNode = objectMapper.readTree(deviceJson);
            if (jsonNode.isArray()) {
                throw new RuntimeException("下发的数据应格式应是Map，而不是List");
            } else if (jsonNode.isObject()) {

                // 获取对比表中的deviceCode集合
                List<String> compareMapperDeviceCodeList = dataCompareMapper.getDeviceCodeList();
                boolean contains1 = compareMapperDeviceCodeList.contains(dispatchLog.deviceCode);

                // 在 ` data_compare` 表中添加下发次数
                if (contains1) {
                    dataCompareMapper.addSendCount(dispatchLog.deviceCode);
                } else {
                    dataCompareMapper.insertInfo(new DataCompareDO(dispatchLog.deviceCode, null, 0, 0, 0, 1, 0));
                }


                // 获取下发数据表中更新数据
                List<String> deviceCodeList = dispatchLogMapper.getDeviceCodeList();
                boolean contains = deviceCodeList.contains(dispatchLog.deviceCode);
                if (contains) {
                    dispatchLogMapper.updateInfo(dispatchLog);
                } else {
                    dispatchLogMapper.addInfo(dispatchLog);
                }
            } else {
                throw new RuntimeException("下发的数据应格式是Map");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void infoStorage(InfoStorageDO infoStorageDO) {
        List<String> deviceCodeList = infoStorageMapper.getDeviceCodeList();
        if (deviceCodeList.contains(infoStorageDO.getDeviceCode())) {
            infoStorageMapper.updateInfo(infoStorageDO);
        } else {
            infoStorageMapper.addInfo(infoStorageDO);
        }
    }
}
